package org.example.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.constant.BusinessEnum;
import org.example.constant.SeckillConstants;
import org.example.domain.Prod;
import org.example.domain.SeckillActivity;
import org.example.domain.SeckillOrder;
import org.example.ex.handler.BusinessException;
import org.example.feign.SeckillProdFeign;
import org.example.mapper.SeckillActivityMapper;
import org.example.mapper.SeckillOrderMapper;
import org.example.model.Result;
import org.example.model.SeckillResult;
import org.example.service.SeckillService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SeckillServiceImpl extends ServiceImpl<SeckillActivityMapper, SeckillActivity> implements SeckillService {

    @Autowired
    private SeckillActivityMapper seckillActivityMapper;

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    @Qualifier("org.example.feign.SeckillProdFeign")
    @Autowired
    private SeckillProdFeign seckillProdFeign;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 订单超时时间(30分钟)
    private static final long ORDER_TIMEOUT = 1 * 60 * 1000;//测试阶段暂定1分钟

    // Redis秒杀商品库存前缀
    private static final String SECKILL_STOCK_PREFIX = "seckill:stock:";

    // Redis用户秒杀记录前缀
    private static final String SECKILL_USER_RECORD_PREFIX = "seckill:user:";



    @Override
    public Result<List<SeckillActivity>> getActiveSeckillActivities() {
        //获取当前时间
        Date nowTime = new Date();
        List<SeckillActivity> activities = seckillActivityMapper.selectList(new LambdaQueryWrapper<SeckillActivity>()
                .eq(SeckillActivity::getStatus, SeckillConstants.STATUS_ACTIVE)
                .le(SeckillActivity::getStartTime, nowTime) // 开始时间 <= 当前时间
                .ge(SeckillActivity::getEndTime, nowTime)); // 结束时间 >= 当前时间
        if (activities.isEmpty()) {
            return Result.fail(BusinessEnum.SECKILLACTIVITY_NOT_EXIST);
        }
        //根据activities获取商品id集合
        List<Long> prodIds = activities.stream().map(SeckillActivity::getProdId).collect(Collectors.toList());
        //远程调用 获取商品信息
        Result<List<Prod>> resultProd = seckillProdFeign.getSeckillProdByProdIds(prodIds);
        if (resultProd.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())) {
            throw new BusinessException("远程调用：根据商品id集合查询商品对象集合失败");
        }

        List<Prod> prodList = resultProd.getData();
        //根据prodList和activities的值根据商品id合并到新的集合中
        List<SeckillActivity> newProdList = new ArrayList<>();
        for (SeckillActivity activity : activities) {
            Prod prod = prodList.stream().filter(p -> p.getProdId().equals(activity.getProdId())).findFirst().orElse(null);
            if (prod != null) {
                activity.setProdName(prod.getProdName());
                activity.setPic(prod.getPic());
                activity.setPrice(prod.getPrice());
                activity.setCountdown(activity.getSecPrice().divide(prod.getPrice(), BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)));
                newProdList.add(activity);
            }
        }

        return Result.success(newProdList);
    }

    @Override
    public Result<SeckillActivity> getSeckillActivityById(Long activityId) {
        SeckillActivity activity = seckillActivityMapper.selectById(activityId);
        if (activity == null) {
            return Result.fail(BusinessEnum.SECKILLACTIVITY_NOT_EXIST);
        }

        // 检查活动状态
        Date now = new Date();
        if (now.before(activity.getStartTime())) {
            activity.setStatus(SeckillConstants.STATUS_NOT_START);
        } else if (now.after(activity.getEndTime())) {
            activity.setStatus(SeckillConstants.STATUS_ENDED);
        } else {
            activity.setStatus(SeckillConstants.STATUS_ACTIVE);
        }

        return Result.success(activity);
    }


    //TODO 点击秒杀按钮后触发秒杀
    @Override
    @Transactional( rollbackFor = Exception.class)
    public SeckillResult executeSeckill(Long activityId, String openId) {

        try {
            // 1. 检查商品是否在秒杀活动中
            String stockKey = SECKILL_STOCK_PREFIX + activityId;
            if (!redisTemplate.hasKey(stockKey)) {
                return new SeckillResult(false, "秒杀活动未开始或已结束", null, null);
            }

            // 2. 检查用户是否已经参与过该商品的秒杀
            String userRecordKey = SECKILL_USER_RECORD_PREFIX + activityId + ":" + openId;
            if (redisTemplate.hasKey(userRecordKey)) {
                return new SeckillResult(false, "您已经参与过该商品的秒杀", null, null);
            }

            // 3. 使用Redis原子操作扣减库存
            Long decrement = redisTemplate.opsForValue().decrement(stockKey);
            if (decrement < 0) {
                // 库存不足，恢复库存计数
                redisTemplate.opsForValue().increment(stockKey);
                return new SeckillResult(false, "商品已被抢购完毕", null, null);
            }

            SeckillActivity activity = seckillActivityMapper.selectById(activityId);

            // 4. 创建订单，状态设为1(待支付)
            SeckillOrder order = new SeckillOrder();
            order.setActivityId(activityId);
            order.setProdId(activity.getProdId());
            order.setOpenId(openId);
            order.setOrderNumber(UUID.randomUUID().toString());
            order.setStatus(1);
            order.setCreateTime(new Date());
            seckillOrderMapper.insert(order);

            //减库存 库存-1 版本号+1
            UpdateWrapper<SeckillActivity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("activity_id", activity.getActivityId())
                    .eq("version", activity.getVersion()) // 添加版本号条件防止并发更新
                    .set("available_stock", activity.getAvailableStock() - 1)
                    .set("version", activity.getVersion() == null ? 1 : activity.getVersion() + 1)
                    .set("update_time", new Date());

            int result = seckillActivityMapper.update(null, updateWrapper);

            // 检查更新是否成功（乐观锁机制）
            if (result == 0) {
                throw new RuntimeException("更新失败，可能由于并发更新导致");
            }

            // 5. 记录用户秒杀记录，防止重复秒杀
            redisTemplate.opsForValue().set(userRecordKey, 1, 1, TimeUnit.DAYS);

            // 6. 发送延迟消息，30分钟后检查订单支付状态
            SeckillOrder orderIds = seckillOrderMapper.selectOne(new LambdaQueryWrapper<SeckillOrder>()
                    .eq(SeckillOrder::getActivityId, activityId)
                    .eq(SeckillOrder::getOpenId, openId));
            sendDelayMessage(orderIds.getOrderId(), ORDER_TIMEOUT);

            log.info("秒杀成功，订单ID: {}", order.getOrderId());
            return new SeckillResult(true, "秒杀成功，请尽快支付", order.getOrderId(), 1);

        } catch (Exception e) {
            log.error("秒杀失败", e);
            // 发生异常时回滚库存
            redisTemplate.opsForValue().increment(SECKILL_STOCK_PREFIX + activityId);
            return new SeckillResult(false, "秒杀失败:" + e.getMessage(), null, null);
        }
    }

    @Override
    public void handleOrderTimeout(Long orderId) {
        // 查询订单当前状态
        SeckillOrder order = seckillOrderMapper.selectById(orderId);
        if (order != null && order.getStatus() == 1) {
            //redis数据回滚
            redisTemplate.opsForValue().increment(SECKILL_STOCK_PREFIX + order.getActivityId());


            // 如果订单仍为待支付状态，则更新为已取消(3)
            order.setStatus(3);
            seckillOrderMapper.updateById(order);

            // 恢复商品库存
            SeckillActivity activity = seckillActivityMapper.selectById(order.getActivityId());
            //获取当前时间
            Date nowTime = new Date();

            UpdateWrapper<SeckillActivity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("activity_id", activity.getActivityId())
                    .eq("version", activity.getVersion()) // 添加版本号条件防止并发更新
                    .set("available_stock", activity.getAvailableStock() + 1)
                    .set("version", activity.getVersion() == null ? 1 : activity.getVersion() + 1)
                    .set("update_time", nowTime);

            int result = seckillActivityMapper.update(null, updateWrapper);

            // 检查更新是否成功（乐观锁机制）
            if (result == 0) {
                throw new RuntimeException("更新失败，可能由于并发更新导致");
            }

            // 删除用户秒杀记录，允许用户重新参与秒杀
            String userRecordKey = SECKILL_USER_RECORD_PREFIX + order.getActivityId() + ":" + order.getOpenId();
            redisTemplate.delete(userRecordKey);

            log.info("订单超时未支付，已取消订单，订单ID: {}", orderId);
        }
    }

    //发送延迟消息
    private void sendDelayMessage(Long orderId, long delay) {
        // 使用RabbitMQ的TTL+死信队列实现延迟消息
        rabbitTemplate.convertAndSend("seckill.dlx.exchange", "seckill.timeout.routingkey",
                orderId, message -> {
                    message.getMessageProperties().setExpiration(String.valueOf(delay));
                    return message;
                });
    }

}
